#include "event_loop.h"
#include "poller.h"
#include "channel.h"
#include "elassert.h"
#define _WINSOCKAPI_
#include <windows.h>
#include "event_fd.h"
#include "timer_queue.h"
using namespace el;

EventLoop::EventLoop()
{
	current_thread_ = GetCurrentThreadId();

	looping_ = false;
	quit_ = false;
	processing_active_ = false;
	processing_pending_ = false;
	poller_ = new Poller();
	event_fd_ = new EventFD(this);
	current_activ__channel_ = NULL;

	timer_queue_ = new TimerQueue(this);
}


EventLoop::~EventLoop()
{
	if (event_fd_)
	{
		delete event_fd_;
	}
	if (poller_)
	{
		delete poller_;
	}
	if (timer_queue_)
	{
		delete timer_queue_;
	}
}

bool EventLoop::loop()
{
	assert(false == looping_);
	assert(isInLoopThread());

	bool rtn = true;
	quit_ = false;
	looping_ = true;

	bool find = false;
	while (!quit_)
	{
		if (!poller_->poll(activ_channels_, find))
		{
			rtn = false;
			break;
		}
		timer_queue_->handleRead();
		if(find) processActivChannels();
		processPendings();
	}
	looping_ = false;
	return rtn;
}

void el::EventLoop::quit()
{
	if (!isInLoopThread())
	{
		queueInLoop(Functor(this, &EventLoop::quit));
	}
	else
	{
		quit_ = true;
	}
}

void el::EventLoop::runInLoop(Functor functor)
{
	if (isInLoopThread())
	{
		functor();
	}
	else
	{
		queueInLoop(functor);
	}
}

void el::EventLoop::queueInLoop(const Functor& funtor)
{
	{
		MutexLockGuard lock(mutex_);
		pending_functions_.push_back(funtor);
	}
	if (!isInLoopThread() || !isProcessingEvent())
	{
		wakeup();
	}
}

bool el::EventLoop::isLooping()
{
	assert(isInLoopThread());
	return looping_;
}

bool el::EventLoop::isInLoopThread()
{
	return GetCurrentThreadId() == current_thread_;
}

bool el::EventLoop::isProcessingEvent()
{
	assert(isInLoopThread());
	return processing_active_;
}

bool el::EventLoop::isProcessingPending()
{
	return processing_pending_;
}

bool el::EventLoop::updateChannel(Channel * channel)
{
	assert(channel->ownerLoop() == this);
	assert(isInLoopThread());
	return poller_->updateChannel(channel);
}

void el::EventLoop::removeChannel(Channel * channel)
{
	assert(channel->ownerLoop() == this);
	assert(isInLoopThread());
	assert(!isProcessingEvent() || (current_activ__channel_ == channel));
	poller_->removeChannel(channel);
}

void el::EventLoop::wakeup()
{
	event_fd_->wakeup();
}

void el::EventLoop::runAfter(unsigned long delay, const Functor& cb)
{
	timer_queue_->addTimer(cb, TimerQueue::now() + delay, 0);
}

void el::EventLoop::runEvery(unsigned long inteval, const Functor& cb)
{
	timer_queue_->addTimer(cb, TimerQueue::now() + inteval, inteval);
}

void el::EventLoop::processActivChannels()
{
	processing_active_ = true;
	for (ChannelVecIt it = activ_channels_.begin(); it != activ_channels_.end(); it++)
	{
		current_activ__channel_ = *it;
		current_activ__channel_->handleEvent();
	}
	current_activ__channel_ = NULL;
	processing_active_ = false;
	activ_channels_.clear();
}

void el::EventLoop::processPendings()
{
	FunctorVec exec_functions;
	{
		MutexLockGuard lock(mutex_);
		std::swap(exec_functions, pending_functions_);
	}
	processing_pending_ = true;
	for (size_t i = 0; i < exec_functions.size(); ++i)
	{
		exec_functions[i]();
	}
	processing_pending_ = false;
}

